﻿<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>关于江雷 About JiangLei</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <style type="text/css">
        .header
        {
            position: relative;
        }
        .reflash
        {
            position: absolute;
            bottom: 5px;
            right: 50px;
        }
        .canvas
        {
            border: #DDF solid 1px;
            border-radius: 10px;
            background: #F7F5FA url(images/cloud.jpg);
            margin: 0;
        }
        .curtain
        {
            position: absolute;
            z-index: -2;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            visibility: hidden;
            background-image: url(images/popbg.png);
        }
        .closeInfo
        {
            position: absolute;
            z-index: -3;
            width: 20px;
            height: 30px;
            top: 120px;
            left: 50%;
            margin-left: 320px;
            visibility: hidden;
            background: url(images/close.png) no-repeat left top;
            cursor: pointer;
        }
        .closeInfoOver
        {
            background: url(images/close.png) no-repeat right top;
        }
        .infoPop
        {
            position: absolute;
            z-index: -3;
            width: 400px;
            height: auto;
            top: 170px;
            left: 50%;
            margin-left: -220px;
            visibility: hidden;
            background: #FFF url(images/pop.png);
            padding: 20px;
            border: 5px solid #FFF;
            border-radius: 10px;
            -webkit-border-radius: 10px;
            -moz-border-radius: 10px;
            color: #254063;
        }
        .info
        {
            float: left;
            margin: 10px 30px;
        }
        .info p span
        {
            width: 80px;
            display: inline-block;
        }
        
        .infoPop p span
        {
            width: 20%;
            display: inline-table;
        }
        .infoPop p .expand
        {
            display: inline-table;
            width: 78%;
        }
        .infoPop p .title
        {
            font-size: 1.5em;
            display: inline;
            width: 100%;
        }
        .infoPop a:link, .infoPop a:visited
        {
            color: #CC3333;
        }
        .infoPop a:hover
        {
            color: #FF6600;
            text-decoration: none;
        }
        .infoPop a:active
        {
            color: #CC3333;
        }
    </style>
</head>
<body>
    <div class="bodyDiv">
        <div class="header">
            <div class="imgB shadow">
                <img src="images/DSCN0318.jpg" alt="jl" class="pic" height="160" />
            </div>
            <p class="nav">
                动态版 | <a href="AboutMeStatic.html">静态版</a></p>
            <div class="info">
                <p class="name">
                    江雷 Jiang Lei</p>
                <p class="lable">
                    ITer &middot; Web前端 &middot; 摄影</p>
                <p>
                    <a href="www.whu.edu.cn">武汉大学</a> - <a href="http://www.iss.whu.edu.cn/">国际软件学院</a>
                    - <a href="http://www.iss.whu.edu.cn/detailForFixed.html?id=187">软件工程</a></p>
                <p>
                    <span>Email : </span><a href="mailto:jianglei.love.you@gmail.com">jianglei.love.you@gmail.com&nbsp;&#9993;</a></p>
            </div>
            <p class="reflash">
                请<a href="#" onclick="javascript:location.href = location.href;">刷新&#8635;</a>页面，观看随机生成页面.</p>
            <div class="clear">
            </div>
        </div>
        <div class="container">
            <canvas id="myCanvas" class="canvas shadow" onmouseover="canvasOver(event)" onmouseout="canvasOut(event)"
                onmousemove="canvasMove(event)" onclick="canvasClick(event)">
        对不起，您的浏览器不支持，请浏览<a href="AboutMeStatic.html">静态版</a>
        </canvas>
        </div>
        <div class="footer">
            &copy;WHU-ISS-JiangLei-武汉大学-国际软件学院-江雷
        </div>
    </div>
    <div id="curtainDiv" class="curtain">
        <div id="closeBtn" class="closeInfo" onclick="fadeOutPop()" onmouseover="this.className = 'closeInfo closeInfoOver'"
            onmouseout="this.className = 'closeInfo'">
        </div>
        <div id="infoPopDiv" class="infoPop shadowDark">
        </div>
    </div>
    <script type="text/javascript">
        //全局变量
        var canvas = document.getElementById("myCanvas");
        canvas.width = 896;
        canvas.height = 420;
        var ctx = canvas.getContext("2d");
        var wd = canvas.width;
        var ht = canvas.height;
        var pi = Math.PI;
        var ballsArr = new Array(); //存储球的基本信息的数组
        var dirInfoArr = new Array(); //存储球在碰撞过程中产生的偏移量信息
        var cvsActLeft = getElementLeft(canvas); //画布相对浏览器的位置
        var cvsActTop = getElementTop(canvas);
        var relX = -1, relY = -1; //鼠标相对画布的位置
        var request; //动画

        //XML文档相关变量
        var xmlUrl = "Work.xml"; //xml文件的路径
        var xmlDoc = loadXmlFile(xmlUrl); //加载xml
        var xmlWorkArr = xmlDoc.getElementsByTagName("Work");
        var xmlWorkNameArr = xmlDoc.getElementsByTagName("Work_Name_Short");

        var N = xmlWorkArr.length, M = 6, off = 0.015; //N:有效信息的个数; off:球运动的速度;M 随机颜色数
        //球 结构体
        function Ball(r, x, y, xDir, yDir, c) {
            this.r = r;
            this.x = x;
            this.y = y;
            this.xDir = xDir;
            this.yDir = yDir;
            this.num = -1;
            this.col = c;
        }
        //方向信息 结构体
        function dirInfo() {
            this.xOff = 0;
            this.yOff = 0;
            this.xDirOff = 0;
            this.yDirOff = 0;
            this.xDirChg = true;
            this.yDirChg = true;
        }
        //动画
        window.requestAnimFrame = (function (callback) {
            return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
        })();
        //停止动画
        window.cancelRequestAnimFrame = (function () {
            return window.cancelAnimationFrame ||
        window.webkitCancelRequestAnimationFrame ||
        window.mozCancelRequestAnimationFrame ||
        window.oCancelRequestAnimationFrame ||
        window.msCancelRequestAnimationFrame ||
		clearTimeout
        })();
        //初始化画布，所有球
        function InitDrawBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr) {
            var i = 0, j = 0;
            ctx.clearRect(0, 0, wd, ht);
            while (j < N) {
                var len = ballsArr.len;
                r = Math.random() * 35 + 25;
                x = Math.random() * (wd - 120) + 60;
                y = Math.random() * (ht - 120) + 60;
                c = Math.floor(Math.random() * 100) % M;
                for (var k = 0; k < len; k++) {
                    var dtX = ballsArr[k].x - x;
                    var dtY = ballsArr[k].y - y;
                    var dt = Math.sqrt(Math.pow(dtX, 2) + Math.pow(dtY, 2));
                    if (dt < r + ballsArr[k].r) continue;
                }
                ag = Math.random() * pi * 2;
                xDir = Math.cos(ag);
                yDir = Math.sin(ag);
                ballsArr[i] = new Ball(r, x, y, xDir, yDir, c);
                dirInfoArr[i] = new dirInfo();
                if (r >= 42) { ballsArr[i].num = j; j++; }
                drawBall(ctx, ballsArr, xmlWorkArr, i);
                i++;
            }
            //检验光标
            if (checkMouseAvailable() >= 0) canvas.style.cursor = "pointer";
            else canvas.style.cursor = "Default";
            controlBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr);
        }
        //控制所有球移动
        function controlBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr) {
            checkBump(ctx, ballsArr, dirInfoArr);
            drawAllBalls(ctx, ballsArr, xmlWorkArr);
            updateDirInfo(ballsArr, dirInfoArr);
            request = requestAnimFrame(function () {
                controlBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr);
            });
        }
        //画所有球
        function drawAllBalls(ctx, ballsArr, xmlWorkArr) {
            ctx.clearRect(0, 0, wd, ht);
            var len = ballsArr.length;
            for (var i = 0; i < len; i++) {
                drawBall(ctx, ballsArr, xmlWorkArr, i);
            }
            if (checkMouseAvailable() >= 0) canvas.style.cursor = "pointer";
            else canvas.style.cursor = "Default";
        }
        //画一个球
        function drawBall(ctx, ballsArr, xmlWorkArr, i) {
            var r = ballsArr[i].r;
            var x = ballsArr[i].x;
            var y = ballsArr[i].y;
            var xDir = ballsArr[i].xDir;
            var yDir = ballsArr[i].yDir;
            var c = ballsArr[i].col;
            var num = ballsArr[i].num;
            var nameNode = xmlWorkNameArr[num];

            ctx.translate(x, y);
            ctx.beginPath();
            ctx.fillStyle = selColor(c);
            ctx.arc(0, 0, r, 0, pi * 2, false);
            ctx.lineWidth = 2;
            ctx.closePath();
            ctx.fill();

            var refX = -1 * r * 0.3, refY = -1 * r * 0.5, refR = r * 0.5;
            var grad = ctx.createRadialGradient(refX, refY, 0, refX, refY, refR);
            grad.addColorStop(0, 'rgba(255,255,255,0.8)');
            grad.addColorStop(1, 'rgba(255,255,255,0)');
            ctx.beginPath();
            ctx.fillStyle = grad;
            ctx.arc(refX, refY, refR, 0, pi * 2, false);
            ctx.closePath();
            ctx.fill();

            if (num >= 0) {
                var txt = nameNode.childNodes[0].nodeValue;
                ctx.fillStyle = '#636363';
                ctx.font = '16px Helvetica Neue , Lucida Grande , Segoe UI , Arial, Helvetica, Verdana, sans-serif';
                ctx.textBaseline = 'top';
                ctx.textAlign = "center";
                var l = r / 10;
                var n = txt.length / l;
                for (var m = 0; m < n; m++) {
                    var txtbuf = txt.substr(m * l, l);
                    ctx.fillText(txtbuf, 0, 24 * m - (n / 2) * 24);
                }
            }
            ctx.translate(-x, -y);
        }
        function selColor(i) {
            if (i == 0) {
                return '#FFEC94';
            }
            if (i == 1) {
                return '#FFAEAE';
            }
            if (i == 2) {
                return '#FFF0AA';
            }
            if (i == 3) {
                return '#B0E57C';
            }
            if (i == 4) {
                return '#B4D8E7';
            }
            if (i == 5) {
                return '#56BAEC';
            }
        }
        //检验球是否发生碰撞
        function checkBump(ctx, ballsArr, dirInfoArr) {
            var len = ballsArr.length;
            for (var i = 0; i < len; i++) {
                for (var j = len - 1; j > i; j--) {
                    checkBallBump(ballsArr, dirInfoArr, i, j);
                }
                checkBumpSide(ballsArr, dirInfoArr, i);
            }
        }
        //判断出界，是否需要改变方向
        function checkBumpSide(ballsArr, dirInfoArr, i) {
            r = ballsArr[i].r;
            xDir = ballsArr[i].xDir;
            yDir = ballsArr[i].yDir;

            ballsArr[i].x += r * xDir * off + dirInfoArr[i].xOff;
            ballsArr[i].y += r * yDir * off + dirInfoArr[i].yOff;

            x = ballsArr[i].x;
            y = ballsArr[i].y;

            //判断球是否撞上边界
            if (x < r) {
                ballsArr[i].x = r;
                dirInfoArr[i].xDirChg = false;
            }
            else if (x > wd - r) {
                ballsArr[i].x = wd - r;
                dirInfoArr[i].xDirChg = false;
            }
            if (y < r) {
                ballsArr[i].y = r;
                dirInfoArr[i].yDirChg = false;
            }
            else if (y > ht - r) {
                ballsArr[i].y = ht - r;
                dirInfoArr[i].yDirChg = false;
            }
        }
        //判断两球是否将发生碰撞，并处理碰撞
        function checkBallBump(ballsArr, dirInfoArr, i, j) {
            var ball1 = ballsArr[i];
            var ball2 = ballsArr[j];

            var r1 = ball1.r;
            var xDir1 = ball1.xDir;
            var yDir1 = ball1.yDir;
            var x1 = ball1.x + r * xDir1 * off;
            var y1 = ball1.y + r * yDir1 * off;

            var r2 = ball2.r;
            var xDir2 = ball2.xDir;
            var yDir2 = ball2.yDir;
            var x2 = ball2.x + r * xDir2 * off;
            var y2 = ball2.y + r * yDir2 * off;

            var deltaX = x2 - x1;
            var deltaY = y2 - y1;
            var deltaXY = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
            var offbase = (r1 + r2 - deltaXY) / (r1 + r2);
            var sinOff = deltaX / deltaXY;
            var cosOff = deltaY / deltaXY;

            if (offbase >= 0)//发生碰撞
            {
                //XY坐标偏移量
                dirInfoArr[i].xOff += r1 * offbase * sinOff * (-1);
                dirInfoArr[i].yOff += r1 * offbase * cosOff * (-1);
                dirInfoArr[j].xOff += r2 * offbase * sinOff;
                dirInfoArr[j].yOff += r2 * offbase * cosOff;

                var l1 = (Math.abs(xDir1) > Math.abs(yDir1)) ? Math.abs(xDir1) : Math.abs(yDir1);
                var l2 = (Math.abs(xDir2) > Math.abs(yDir2)) ? Math.abs(xDir2) : Math.abs(yDir2);
                //XY方向偏移量
                dirInfoArr[i].xDirOff += l1 * sinOff * (-2);
                dirInfoArr[i].yDirOff += l1 * cosOff * (-2);
                dirInfoArr[j].xDirOff += l2 * sinOff * 2;
                dirInfoArr[j].yDirOff += l2 * cosOff * 2;
            }
        }
        //检验是否需要改变方向，并更新方向信息
        function updateDirInfo(ballsArr, dirInfoArr) {
            var len = ballsArr.length;
            for (var i = 0; i < len; i++) {
                if (dirInfoArr[i].xDirOff != 0 || dirInfoArr[i].yDirOff != 0) {
                    ballsArr[i].xDir += dirInfoArr[i].xDirOff;
                    ballsArr[i].yDir += dirInfoArr[i].yDirOff;

                    var dtX = ballsArr[i].xDir;
                    var dtY = ballsArr[i].yDir;
                    var dt = Math.sqrt(Math.pow(dtX, 2) + Math.pow(dtY, 2));
                    //保证X，Y速度为单位速度
                    ballsArr[i].xDir = dtX / dt;
                    ballsArr[i].yDir = dtY / dt;
                }
                if (dirInfoArr[i].xDirChg == false) {
                    ballsArr[i].xDir *= -1;
                }
                if (dirInfoArr[i].yDirChg == false) {
                    ballsArr[i].yDir *= -1;
                }
                dirInfoArr[i].xOff = 0;
                dirInfoArr[i].yOff = 0;
                dirInfoArr[i].xDirOff = 0;
                dirInfoArr[i].yDirOff = 0;
                dirInfoArr[i].xDirChg = true;
                dirInfoArr[i].yDirChg = true;
            }
        }
        //加载xml文件
        function loadXmlFile(xmlUrl) {
            xmlDoc = null;
            try//IE
        {
                xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
                xmldoc.async = false; //必须同步
                xmlDoc.load(xmlUrl);
            }
            catch (e) {
                try//other Explorer
            {
                    xmlDoc = document.implementation.createDocument("", "", null);
                    try {
                        var xmlhttp = new window.XMLHttpRequest();
                        xmlhttp.open("GET", xmlUrl, false); //必须同步
                        xmlhttp.send(null);
                        xmlDoc = xmlhttp.responseXML;
                    }
                    catch (e) { alert(e.message) }
                }
                catch (e) { alert(e.message) }
            }
            return xmlDoc;
        }
        //计算元素相对于浏览器的left
        function getElementLeft(element) {
            var actualLeft = element.offsetLeft;
            var current = element.offsetParent;
            while (current !== null) {
                actualLeft += current.offsetLeft;
                current = current.offsetParent;
            }
            return actualLeft;
        }
        //计算元素相对于浏览器的top
        function getElementTop(element) {
            var actualTop = element.offsetTop;
            var current = element.offsetParent;
            while (current !== null) {
                actualTop += current.offsetTop;
                current = current.offsetParent;
            }
            return actualTop;
        }
        //canvas 鼠标点击事件
        function canvasClick(e) {
            relX = e.clientX - cvsActLeft;
            relY = e.clientY - cvsActTop;
            var h = checkMouseAvailable();
            if (h >= 0) {
                canvas.style.cursor = "pointer";
                //暂停动画
                cancelRequestAnimFrame(request);
                popInfo(xmlWorkArr, h);
            }
            else {
                canvas.style.cursor = "Default";
            }
        }
        //canvas 鼠标经过事件
        function canvasOver(e) {
            relX = e.clientX - cvsActLeft;
            relY = e.clientY - cvsActTop;
            if (checkMouseAvailable() >= 0) canvas.style.cursor = "pointer";
            else canvas.style.cursor = "Default";
        }
        //canvas 鼠标移动事件
        function canvasMove(e) {
            relX = e.clientX - cvsActLeft;
            relY = e.clientY - cvsActTop;
            if (checkMouseAvailable() >= 0) canvas.style.cursor = "pointer";
            else canvas.style.cursor = "Default";
        }
        //canvas 鼠标离开事件
        function canvasOut(e) {
            relX = -1; relY = -1;
            canvas.style.cursor = "Default";
        }
        //检验鼠标是否在活动区域
        function checkMouseAvailable() {
            var len = ballsArr.length;
            for (var i = 0; i < len; i++) {
                if (ballsArr[i].num >= 0 && Math.sqrt(Math.pow((ballsArr[i].x - relX), 2) + Math.pow((ballsArr[i].y - relY), 2)) < ballsArr[i].r) {
                    return ballsArr[i].num;
                }
            }
            return -1;
        }
        //弹出项目信息
        function popInfo(xmlWorkArr, i) {
            var curtain = document.getElementById("curtainDiv");
            var infoPop = document.getElementById('infoPopDiv');
            var closePop = document.getElementById('closeBtn');
            curtain.style.visibility = "visible";
            curtain.style.zIndex = "2";
            infoPop.style.visibility = "visible";
            infoPop.style.zIndex = "3";
            closePop.style.visibility = "visible";
            closePop.style.zIndex = "3";

            var txt = "";
            var work = xmlWorkArr[i]
            if (work.getElementsByTagName("Work_Name")[0].childNodes[0] != null) {
                txt += '<div><p><span class="title expand">&#10000;&nbsp;' + work.getElementsByTagName("Work_Name")[0].childNodes[0].nodeValue + '</span>';
            }
            if (work.getElementsByTagName("Work_Time")[0].childNodes[0] != null) {
                txt += '<p><span class="expand">&nbsp;&nbsp;&nbsp;' + work.getElementsByTagName("Work_Time")[0].childNodes[0].nodeValue + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Org")[0].childNodes[0] != null) {
                txt += '<p><span>机构:</span><span class="expand">' + work.getElementsByTagName("Work_Org")[0].childNodes[0].nodeValue + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Dscrp")[0].childNodes[0] != null) {
                txt += '<p><span>描述:</span><span class="expand">' + work.getElementsByTagName("Work_Dscrp")[0].childNodes[0].nodeValue + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Rspns")[0].childNodes[0] != null) {
                txt += '<p><span>负责:</span><span class="expand">' + work.getElementsByTagName("Work_Rspns")[0].childNodes[0].nodeValue + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Skill")[0].childNodes[0] != null) {
                txt += '<p><span>编程语言:</span><span class="expand">' + work.getElementsByTagName("Work_Skill")[0].childNodes[0].nodeValue + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Link")[0].childNodes[0] != null) {
                var linkNode = work.getElementsByTagName("Work_Link")[0].getElementsByTagName("Work_Link_Li");
                var len = linkNode.length, textBuf = "";

                for (var i = 0; i < len; i++) {
                    textBuf += '<a href=' + linkNode[i].childNodes[0].nodeValue + ' target="_blank">' +
					linkNode[i].getElementsByTagName("Work_Link_Li_Text")[0].childNodes[0].nodeValue + '</a>	'
                }
                txt += '<p><span>相关链接:</span><span class="expand">' + textBuf + '</span><p/>';
            }
            if (work.getElementsByTagName("Work_Award")[0].childNodes[0] != null) {
                txt += '<p><span>奖励:</span><span class="expand">' + work.getElementsByTagName("Work_Award")[0].childNodes[0].nodeValue + '</span><p/></div>';
            }
            infoPop.innerHTML = txt;
        }
        //弹出信息消失
        function fadeOutPop() {
            var curtain = document.getElementById("curtainDiv");
            var infoPop = document.getElementById('infoPopDiv');
            var closePop = document.getElementById('closeBtn');
            curtain.style.visibility = "hidden";
            curtain.style.zIndex = "-2";
            infoPop.style.visibility = "hidden";
            infoPop.style.zIndex = "-3";
            infoPop.innerHTML = "";
            closePop.style.visibility = "hidden";
            closePop.style.zIndex = "-3";
            //重新启动动画
            controlBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr);
        }

        //函数入口
        window.onload = InitDrawBalls(ctx, ballsArr, dirInfoArr, xmlWorkArr);
    </script>
</body>
</html>
